package moe.dao;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.util.logging.Logger;

import moe.entity.Column;
import moe.entity.Transient;

public class AnnotationColumnMapper {
	private static final Logger log = Logger.getLogger(AnnotationColumnMapper.class.getName());

	public static <T> T resultSetMap(ResultSet rs, T bean) {
		Field[] fields = bean.getClass().getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			if (field.getAnnotation(Transient.class) != null) {
				continue;
			}
			String colName = getColumnName(field);
			String className = getClassName(field);
			Method method = getMethod(rs, className);
			try {
				method.setAccessible(true);
				Object result = method.invoke(rs, colName);
				field.set(bean, result);
			} catch (Exception e) {
				e.printStackTrace();
				log.warning("Field: \"" + field.getName() + "\" can't set value, column: "
						+ colName);
				continue;
			}
		}
		return bean;
	}

	public static <T> String mappingToInsert(String table, T bean) {
		StringBuilder columns = new StringBuilder();
		StringBuilder values = new StringBuilder();

		for (Field field : bean.getClass().getDeclaredFields()) {
			field.setAccessible(true);
			if (field.getAnnotation(Transient.class) != null) {
				continue;
			}

			String colName = getColumnName(field);
			String value = null;
			try {
				value = field.get(bean).toString();
			} catch (Exception e) {
				log.warning("Field: \"" + field.getName() + "\" can't read value, column: "
						+ colName);
				continue;
			}
			if (field.getType() == String.class) {
				value = value.replaceAll("'", "''");
				value = "'" + value + "'";
			} else if (field.getType() == Boolean.class) {
				value = value.toUpperCase().equals("TRUE") ? "1" : "0";
			}
			columns.append(", `").append(colName).append("`");
			values.append(", ").append(value);
		}
		StringBuilder result = new StringBuilder();
		result.append("INSERT INTO `")
				.append(table)
				.append("` (")
				.append(columns.substring(2))
				.append(") VALUES(")
				.append(values.substring(2))
				.append(")");
		return result.toString();
	}

	private static <T> Method getMethod(T obj, String typeName) {
		typeName = typeName.toLowerCase();
		typeName = typeName.replaceFirst("^.{1}", String.valueOf(typeName.charAt(0)).toUpperCase());
		String methodName = "get" + typeName;
		Method method = null;
		try {
			method = obj.getClass().getMethod(methodName, String.class);
		} catch (NoSuchMethodException e1) {
			methodName = "get" + typeName.substring(0, 3);
			try {
				method = obj.getClass().getMethod(methodName, String.class);
			} catch (NoSuchMethodException e2) {
				method = null;
			}
		}
		return method;
	}

	private static String getColumnName(Field field) {
		String colName = field.getName();
		Column col = field.getAnnotation(Column.class);
		if (col != null && !col.name().equals("")) {
			colName = col.name();
		}
		return colName;
	}

	private static String getClassName(Field field) {
		String name = field.getType().getName();
		return name.substring(name.lastIndexOf(".") + 1);
	}
}
